package com.cloudweb.oa.controller;

import cn.js.fan.util.ErrMsgException;
import cn.js.fan.util.ParamUtil;
import cn.js.fan.util.StrUtil;
import cn.js.fan.util.file.FileUtil;
import cn.js.fan.web.Global;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloudweb.oa.api.ILicenseUtil;
import com.cloudweb.oa.cache.GroupCache;
import com.cloudweb.oa.cache.RoleCache;
import com.cloudweb.oa.cache.UserCache;
import com.cloudweb.oa.entity.Group;
import com.cloudweb.oa.entity.Role;
import com.cloudweb.oa.entity.User;
import com.cloudweb.oa.security.AuthUtil;
import com.cloudweb.oa.utils.ConstUtil;
import com.cloudweb.oa.utils.LicenseConstUtil;
import com.cloudweb.oa.vo.Result;
import com.cloudwebsoft.framework.util.LogUtil;
import com.redmoon.oa.Config;
import com.redmoon.oa.basic.TreeSelectDb;
import com.redmoon.oa.basic.TreeSelectView;
import com.redmoon.oa.flow.*;
import com.redmoon.oa.flow.macroctl.MacroCtlMgr;
import com.redmoon.oa.flow.macroctl.MacroCtlUnit;
import com.redmoon.oa.flow.query.QueryScriptUtil;
import com.redmoon.oa.flow.strategy.StrategyMgr;
import com.redmoon.oa.flow.strategy.StrategyUnit;
import com.redmoon.oa.kernel.License;
import com.redmoon.oa.person.UserDb;
import com.redmoon.oa.pvg.Privilege;
import com.redmoon.oa.pvg.RoleDb;
import io.swagger.annotations.*;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

@Api(tags = "预定义流程模块")
@Controller
@RequestMapping("/admin")
public class WorkflowPredefineController {
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private AuthUtil authUtil;

    @Autowired
    private UserCache userCache;

    @Autowired
    private RoleCache roleCache;

    @Autowired
    private GroupCache groupCache;

    @Autowired
    private ILicenseUtil licenseUtil;

    @ApiOperation(value = "设置调试模式", notes = "设置调试模式", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "流程类型编码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "isDebug", value = "是否调试模式", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/setDebugMode", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> setDebugMode(@RequestParam(value = "code") String code, @RequestParam(value = "isDebug", defaultValue = "false") Boolean isDebug) throws ErrMsgException {
        Privilege privilege = new Privilege();
        Leaf lf = new Leaf();
        lf = lf.getLeaf(code);
        String myUnitCode = privilege.getUserUnitCode(request);
        LeafPriv lp = new LeafPriv(code);
        if (privilege.isUserPrivValid(request, "admin.unit") && lf.getUnitCode().equals(myUnitCode)) {
        } else if (!lp.canUserExamine(privilege.getUser(request))) {
            return new Result<>(false, "权限非法");
        }

        if (lf.getChildCount() > 0) {
            Vector<Leaf> v = new Vector<>();
            lf.getAllChild(v, lf);
            v.addElement(lf);
            for (Leaf leaf : v) {
                lf = leaf;
                if (lf.getType() != Leaf.TYPE_NONE) {
                    lf.setDebug(isDebug);
                    lf.update();
                }
            }
        } else {
            lf.setDebug(isDebug);
            lf.update();
        }
        return new Result<>();
    }

    @ApiOperation(value = "删除节点", notes = "删除节点", httpMethod = "POST")
    @ApiImplicitParam(name = "code", value = "节点编码", required = true, dataType = "String")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/delNode", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> delNode(@RequestParam(value = "code") String code) throws ErrMsgException {
        Directory dir = new Directory();
        try {
            dir.del(request, code);
        } catch (ErrMsgException e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>();
    }

    @ApiOperation(value = "移动节点", notes = "移动节点", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/moveNode", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> moveNode() throws ErrMsgException {
        String code = ParamUtil.get(request, "code");
        String parentCode = ParamUtil.get(request, "parent_code");
        int position = Integer.parseInt(ParamUtil.get(request, "position"));
        if ("root".equals(code)) {
            return new Result<>(false, "根节点不能移动");
        }
        if ("#".equals(parentCode)) {
            return new Result<>(false, "不能与根节点平级");
        }

        Directory dir = new Directory();
        Leaf moveleaf = dir.getLeaf(code);
        String oldParentCode = moveleaf.getParentCode();
        int oldPosition = moveleaf.getOrders();//得到被移动节点原来的位置，从1开始

        Leaf oldParentLeaf = dir.getLeaf(oldParentCode);
        Leaf newParentLeaf;
        if (parentCode.equals(oldParentCode)) {
            newParentLeaf = oldParentLeaf;
        } else {
            newParentLeaf = dir.getLeaf(parentCode);
        }
        // 移动后的层级需一致
        if (oldParentLeaf.getLayer() != newParentLeaf.getLayer()) {
            return new Result<>(false, "层级不一致，不能移动");
        }
        int p = position + 1;  // jstree的position是从0开始的，而orders是从1开始的
        moveleaf.setParentCode(parentCode);
        moveleaf.setOrders(p);
        moveleaf.update();

        boolean isSameParent = oldParentCode.equals(parentCode);

        // 重新梳理orders
        for (Leaf lf : newParentLeaf.getChildren()) {
            // 跳过自己
            if (lf.getCode().equals(code)) {
                continue;
            }

            // 如果移动后父节点变了
            if (!isSameParent) {
                if (lf.getOrders() >= p) {
                    lf.setOrders(lf.getOrders() + 1);
                    lf.update();
                }
            } else {
                if (p < oldPosition) {//上移
                    if (lf.getOrders() >= p) {
                        lf.setOrders(lf.getOrders() + 1);
                        lf.update();
                    }
                } else {//下移
                    if (lf.getOrders() <= p && lf.getOrders() > oldPosition) {
                        lf.setOrders(lf.getOrders() - 1);
                        lf.update();
                    }
                }
            }
        }

        // 原节点下的孩子节点通过修复repairTree处理
        Leaf rootLeaf = dir.getLeaf(Leaf.CODE_ROOT);
        Directory dm = new Directory();
        try {
            dm.repairTree(rootLeaf);
        } catch (Exception e) {
            LogUtil.getLog(getClass()).error(e);
        }

        // 父节点有变化
        if (!isSameParent) {
            // 只有二级节点的父节点才会有变化，此时需变动其表单所属的类别
            FormDb fd = new FormDb();
            fd = fd.getFormDb(moveleaf.getFormCode());
            fd.setFlowTypeCode(parentCode);
            fd.saveContent();

            // 修改流程记录中的parentTypeCode
            WorkflowDb wf = new WorkflowDb();
            Vector<WorkflowDb> v = wf.listByTypeCode(code);
            for (WorkflowDb workflowDb : v) {
                workflowDb.setParentTypeCode(parentCode);
                workflowDb.save();
            }
        }
        return new Result<>();
    }

    @ApiOperation(value = "创建节点", notes = "创建节点", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/createNode", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> createNode() throws ErrMsgException {
        Directory dir = new Directory();
        boolean re = false;
        try {
            re = dir.AddChild(request);
        } catch (ErrMsgException e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "更新节点", notes = "更新节点", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateNode", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> updateNode() throws ErrMsgException {
        boolean re;
        Directory dir = new Directory();
        try {
            re = dir.update(request);
        } catch (ErrMsgException e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "编辑时获取节点属性", notes = "编辑时获取节点属性", httpMethod = "POST")
    @ApiImplicitParam(name = "code", value = "节点编码", required = true, dataType = "String")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @PreAuthorize("hasAnyAuthority('admin', 'admin.flow', 'admin.unit')")
    @ResponseBody
    @RequestMapping(value = "/flow/editNode", produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> editNode(@RequestParam String code) {
        // 如果是根节点
        if ("root".equals(code)) {
            // 如果是子单位人员
            if (!ConstUtil.DEPT_ROOT.equals(authUtil.getUserUnitCode())) {
                JSONObject json = new JSONObject();
                json.put("isPvgNotValid", true);
                return new Result<>(json);
            }
        }
        Leaf lf = new Leaf();
        lf = lf.getLeaf(code);
        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(lf);
        if (lf.getQueryId() != Leaf.QUERY_NONE) {
            FormQueryDb aqd = new FormQueryDb();
            aqd = aqd.getFormQueryDb((int) lf.getQueryId());
            jsonObject.put("queryName", aqd.getQueryName());
        }

        jsonObject.put("isCircleReadEnabled", licenseUtil.isEnabled(LicenseConstUtil.CIRCLE_READ));

        return new Result<>(jsonObject);
    }

    @ApiOperation(value = "套用流程图", notes = "套用流程图", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "当前流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "templateCode", value = "被套用的流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "isWithScript", value = "套用流程时是否同时附带事件脚本", required = true, dataType = "Boolean"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/applyWorkflow", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> applyWorkflow(@RequestParam(value = "typeCode") String flowTypeCode, @RequestParam(value = "templateCode") String templateCode, @RequestParam(value = "isWithScript") boolean isWithScript) {
        boolean re;
        try {
            WorkflowPredefineDb wpd = new WorkflowPredefineDb();
            wpd = wpd.getDefaultPredefineFlow(flowTypeCode);

            String title = "";
            Leaf lf = new Leaf();
            lf = lf.getLeaf(flowTypeCode);
            if (lf != null) {
                title = lf.getName();
            }

            // 如果还没有预定义流程
            if (wpd == null) {
                wpd = new WorkflowPredefineDb();
                WorkflowPredefineDb twpd = wpd.getDefaultPredefineFlow(templateCode);
                if (twpd == null || !twpd.isLoaded()) {
                    return new Result<>(false, "流程图不存在");
                }
                wpd.setTypeCode(flowTypeCode);
                wpd.setFlowString(twpd.getFlowString());
                wpd.setTitle(title);
                wpd.setReturnBack(twpd.isReturnBack());
                wpd.setReactive(twpd.isReactive());
                wpd.setRecall(twpd.isRecall());
                wpd.setReturnMode(twpd.getReturnMode());
                wpd.setReturnStyle(twpd.getReturnStyle());
                wpd.setRoleRankMode(twpd.getRoleRankMode());
                wpd.setProps(twpd.getProps());
                wpd.setViews(twpd.getViews());
                if (isWithScript) {
                    wpd.setScripts(twpd.getScripts());
                }
                wpd.setLinkProp(twpd.getLinkProp());
                wpd.setFlowJson(twpd.getFlowJson());
                re = wpd.create();
            } else {
                WorkflowPredefineDb twpd = wpd.getDefaultPredefineFlow(templateCode);
                if (twpd == null || !twpd.isLoaded()) {
                    return new Result<>(false, "流程图不存在");
                }
                wpd.setFlowString(twpd.getFlowString());
                wpd.setReturnBack(twpd.isReturnBack());
                wpd.setReactive(twpd.isReactive());
                wpd.setRecall(twpd.isRecall());
                wpd.setReturnMode(twpd.getReturnMode());
                wpd.setReturnStyle(twpd.getReturnStyle());
                wpd.setRoleRankMode(twpd.getRoleRankMode());
                wpd.setProps(twpd.getProps());
                wpd.setViews(twpd.getViews());
                if (isWithScript) {
                    wpd.setScripts(twpd.getScripts());
                }
                wpd.setLinkProp(twpd.getLinkProp());
                wpd.setFlowJson(twpd.getFlowJson());
                re = wpd.save();
            }
        } catch (ErrMsgException e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "流程权限列表", notes = "流程权限列表", httpMethod = "POST")
    @ApiImplicitParam(name = "code", value = "流程类型编码", required = true, dataType = "String")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/listPriv", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> listPriv(@RequestParam(value = "code") String code) {
        JSONArray arr = new JSONArray();
        LeafPriv leafPriv = new LeafPriv(code);
        if (!(leafPriv.canUserExamine(authUtil.getUserName()))) {
            return new Result<>(false, cn.js.fan.web.SkinUtil.LoadString(request, "pvg_invalid") + " 用户需对该节点拥有管理的权限");
        }
        Directory dir = new Directory();
        String sql = "select id from flow_dir_priv dp where dp.dir_code=" + StrUtil.sqlstr(code) + " order by id desc";
        Vector v = leafPriv.list(sql);
        for (Object o : v) {
            leafPriv = (LeafPriv)o;
            JSONObject json = new JSONObject();
            json.put("id", leafPriv.getId());
            json.put("name", leafPriv.getName());
            if (leafPriv.getType() == LeafPriv.TYPE_USER) {
                User user = userCache.getUser(leafPriv.getName());
                if (user != null) {
                    json.put("title", user.getRealName());
                } else {
                    json.put("title", "不存在");
                }
            } else if (leafPriv.getType() == LeafPriv.TYPE_USERGROUP) {
                Group group = groupCache.getGroup(leafPriv.getName());
                if (group != null) {
                    json.put("title", group.getDescription());
                } else {
                    json.put("title", "不存在");
                }
            } else {
                Role role = roleCache.getRole(leafPriv.getName());
                if (role != null) {
                    json.put("title", role.getDescription());
                } else {
                    json.put("title", "不存在");
                }
            }
            json.put("see", leafPriv.getSee());
            json.put("modify", leafPriv.getModify());
            json.put("examine", leafPriv.getExamine());
            json.put("typeDesc", leafPriv.getTypeDesc());
            json.put("dirCode", leafPriv.getDirCode());
            json.put("append", leafPriv.getAppend());
            Leaf lf = dir.getLeaf(leafPriv.getDirCode());
            json.put("dirName", lf == null ? "" : lf.getName(request));
            arr.add(json);
        }
        return new Result<>(arr);
    }

    @ApiOperation(value = "添加流程权限", notes = "添加流程权限", httpMethod = "POST")
    @ApiImplicitParam(name = "jsonObject", value = "参数", required = true, dataType = "JSONObject")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/createPriv", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> createPriv(@RequestBody JSONObject jsonObject) {
        String nodeCode = jsonObject.getString("nodeCode");
        JSONArray privs = jsonObject.getJSONArray("privs");
        boolean re = false;
        for (Object o : privs) {
            JSONObject json = (JSONObject)o;
            if (json.getIntValue("type") == LeafPriv.TYPE_USER) {
                UserDb user = new UserDb();
                user = user.getUserDb(json.getString("name"));
                if (!user.isLoaded()) {
                    continue;
                }
            }
            LeafPriv leafPriv = new LeafPriv(nodeCode);
            try {
                re = leafPriv.add(json.getString("name"), json.getIntValue("privType"));
            } catch (ErrMsgException e) {
                return new Result<>(false, e.getMessage());
            }
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "修改流程权限", notes = "修改流程权限", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "ID", dataType = "id"),
            @ApiImplicitParam(name = "see", value = "发起", dataType = "Integer"),
            @ApiImplicitParam(name = "modify", value = "查询", dataType = "Integer"),
            @ApiImplicitParam(name = "examine", value = "管理", dataType = "Integer"),
            @ApiImplicitParam(name = "append", value = "督办", dataType = "Integer"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updatePriv", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updatePriv(@RequestParam(value = "id") Integer id, @RequestParam(value = "see", defaultValue = "0") Integer see,
                                     @RequestParam(value = "modify", defaultValue = "0") Integer modify,
                                     @RequestParam(value = "examine", defaultValue = "0") Integer examine,
                                     @RequestParam(value = "append", defaultValue = "0") Integer append) {
        int del = 0;
        LeafPriv leafPriv = new LeafPriv();
        leafPriv = leafPriv.getLeafPriv(id);
        leafPriv.setAppend(append);
        leafPriv.setModify(modify);
        leafPriv.setDel(del);
        leafPriv.setSee(see);
        leafPriv.setExamine(examine);
        return new Result<>(leafPriv.save());
    }

    @ApiOperation(value = "删除流程权限", notes = "删除流程权限", httpMethod = "POST")
    @ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "Integer")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/delPriv", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> delPriv(@RequestParam(value = "id") Integer id) {
        LeafPriv lp = new LeafPriv();
        lp = lp.getLeafPriv(id);
        return new Result<>(lp.del());
    }

    @ApiOperation(value = "获取流程图", notes = "获取流程图", httpMethod = "POST")
    @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getFlowJson", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getFlowJson(@RequestParam(value = "typeCode") String typeCode) {
        WorkflowPredefineDb workflowPredefineDb = new WorkflowPredefineDb();
        workflowPredefineDb = workflowPredefineDb.getDefaultPredefineFlow(typeCode);
        JSONObject jsonObject = new JSONObject();
        if (workflowPredefineDb == null) {
            Leaf lf = new Leaf();
            lf = lf.getLeaf(typeCode);
            if (lf == null) {
                return new Result<>(false, "类型: " + typeCode + " 不存在");
            }
            workflowPredefineDb = new WorkflowPredefineDb();
            workflowPredefineDb.setTypeCode(typeCode);
            workflowPredefineDb.setFlowJson("{}");
            workflowPredefineDb.setDefaultFlow(true);
            workflowPredefineDb.setTitle(lf.getName());
            workflowPredefineDb.create();
            return new Result<>(jsonObject);
        }
        /*try {
            org.json.JSONObject flowJsonObject = new org.json.JSONObject(WorkflowActionDb.tran(workflowPredefineDb.getFlowJson()));
            jsonObject = (JSONObject)JSONObject.parse(flowJsonObject.toString());
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
        }
        return new Result<>(jsonObject);*/

        JSONObject json = new JSONObject();
        json.put("flowJson", workflowPredefineDb.getFlowJson());
        json.put("licenseKey", License.getInstance().getKey());
        return new Result<>(json);
    }

    @ApiOperation(value = "取流程中的节点", notes = "取流程中的节点，用于流程中的显示规则", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型编码", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getActionsForProcess", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getActionsForProcess(@RequestParam(value = "typeCode") String typeCode) {
        WorkflowPredefineDb workflowPredefineDb = new WorkflowPredefineDb();
        workflowPredefineDb = workflowPredefineDb.getDefaultPredefineFlow(typeCode);

        WorkflowActionDb wad = new WorkflowActionDb();
        JSONArray arr = new JSONArray();
        try {
            org.json.JSONObject flowJsonObject = new org.json.JSONObject(WorkflowActionDb.tran(workflowPredefineDb.getFlowJson()));
            org.json.JSONObject stateJsonObject = flowJsonObject.getJSONObject("states");
            Iterator ir = stateJsonObject.keys();
            while (ir.hasNext()) {
                String key = (String) ir.next();
                org.json.JSONObject state = stateJsonObject.getJSONObject(key);
                org.json.JSONObject props = state.getJSONObject("props");
                String title = wad.tranReverseForFlowJson(props.getJSONObject("ActionTitle").getString("value"));
                String jobName = wad.tranReverseForFlowJson(props.getJSONObject("ActionJobName").getString("value"));
                JSONObject json = new JSONObject();
                json.put("internalName", state.getString("ID"));
                json.put("jobName", WorkflowActionDb.tran(WorkflowActionDb.tranForFlowJson(jobName)).replaceAll("comma", ""));
                json.put("title", title);
                arr.add(json);
            }
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
        }

        return new Result<>(arr);
    }

    @ApiOperation(value = "取流程中的节点", notes = "取流程中的节点，用于所选节点上的人员", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "flowJson", value = "流程图描述json", required = true, dataType = "String"),
            @ApiImplicitParam(name = "internalName", value = "流程节点内部名称，当取所选节点上的人员时internalName需填写（排除该节点上的人员），如不填则取全部节点", dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getActionsForProcessByFlowJson", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getActionsForProcessByFlowJson(@RequestParam(value = "flowJson") String flowJson, @RequestParam(value = "internalName", required = false)String internalName) {
        WorkflowActionDb wad = new WorkflowActionDb();
        JSONArray arr = new JSONArray();
        try {
            org.json.JSONObject flowJsonObject = new org.json.JSONObject(WorkflowActionDb.tran(flowJson));
            org.json.JSONObject stateJsonObject = flowJsonObject.getJSONObject("states");
            Iterator ir = stateJsonObject.keys();
            while (ir.hasNext()) {
                String key = (String) ir.next();
                org.json.JSONObject state = stateJsonObject.getJSONObject(key);
                // internalName为null，则取全部的节点
                if (StrUtil.isEmpty(internalName) || !state.getString("ID").equals(internalName)) {
                    org.json.JSONObject props = state.getJSONObject("props");
                    String title = wad.tranReverseForFlowJson(props.getJSONObject("ActionTitle").getString("value"));
                    String jobName = wad.tranReverseForFlowJson(props.getJSONObject("ActionJobName").getString("value"));
                    JSONObject json = new JSONObject();
                    json.put("internalName", state.getString("ID"));
                    json.put("jobName", jobName);
                    json.put("title", title);
                    arr.add(json);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return new Result<>(arr);
    }

    @ApiOperation(value = "获取分配策略", notes = "获取分配策略", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/listTaskStrategy", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> listTaskStrategy() {
        JSONArray arr = new JSONArray();
        StrategyMgr sm = new StrategyMgr();
        Vector smv = sm.getAllStrategy();
        if (smv != null) {
            for (Object o : smv) {
                StrategyUnit su = (StrategyUnit) o;
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("code", su.getCode());
                jsonObject.put("selectable", su.getIStrategy().isSelectable());
                jsonObject.put("name", su.getName());
                arr.add(jsonObject);
            }
        }
        return new Result<>(arr);
    }

    @ApiOperation(value = "获取视图", notes = "获取视图", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型编码", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/listView", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> listView(@RequestParam(value = "typeCode") String typeCode) {
        Leaf lf = new Leaf();
        lf = lf.getLeaf(typeCode);
        JSONArray arr = new JSONArray();
        FormViewDb fvd = new FormViewDb();
        for (Object o : fvd.getViews(lf.getFormCode())) {
            fvd = (FormViewDb) o;
            JSONObject json = new JSONObject();
            json.put("id", fvd.getInt("id"));
            json.put("name", fvd.getString("name"));
            arr.add(json);
        }
        return new Result<>(arr);
    }

    @ApiOperation(value = "获取流程图的属性", notes = "获取流程图的属性", httpMethod = "POST")
    @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getWorkflowProps", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getWorkflowProps(@RequestParam(value = "typeCode") String typeCode) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        if (wpd == null) {
            return new Result<>();
        }

        LeafPriv lp = new LeafPriv(typeCode);
        if (!(lp.canUserExamine(authUtil.getUserName()))) {
            throw new ErrMsgException(cn.js.fan.web.SkinUtil.LoadString(request, "pvg_invalid"));
        }

        String title = "";
        String dirCode = "";
        int examine = 0;
        title = wpd.getTitle();
        dirCode = wpd.getDirCode();
        examine = wpd.getExamine();
        com.redmoon.oa.Config cfg = new com.redmoon.oa.Config();
        String flowExpireUnit = cfg.get("flowExpireUnit");
        if ("day".equals(flowExpireUnit)) {
            flowExpireUnit = "天";
        } else {
            flowExpireUnit = "小时";
        }

        com.redmoon.oa.kernel.License license = com.redmoon.oa.kernel.License.getInstance();
        JSONObject json = new JSONObject();
        json.put("isPlatform", license.isPlatform());

        json.put("title", title);

        JSONArray jsonArray = new JSONArray();
        TreeSelectDb treeSelectDb = new TreeSelectDb();
        treeSelectDb = treeSelectDb.getTreeSelectDb(ConstUtil.FILEARK_DIR);
        TreeSelectView treeSelectView = new TreeSelectView(treeSelectDb);
        treeSelectView.getTree(request, treeSelectDb);
        jsonArray.add(treeSelectDb);

        json.put("dirTree", jsonArray);
        json.put("dirCode", dirCode);
        json.put("examine", examine);
        json.put("isReactive", wpd.isReactive());
        json.put("isRecall", wpd.isRecall());
        json.put("isDistribute", wpd.isDistribute());
        json.put("isPlus", wpd.isPlus());
        json.put("isTransfer", wpd.isTransfer());
        json.put("isReply", wpd.isReply());
        json.put("isModuleFilter", wpd.isModuleFilter());
        json.put("downloadCount", wpd.getDownloadCount());
        json.put("canDelOnReturn", wpd.isCanDelOnReturn());
        json.put("returnMode", wpd.getReturnMode());
        json.put("returnStyle", wpd.getReturnStyle());
        json.put("roleRankMode", wpd.getRoleRankMode());
        json.put("id", wpd.getId());
        json.put("flowExpireUnit", flowExpireUnit);
        json.put("props", wpd.getProps());
        json.put("msgProps", wpd.getMsgProp());
        json.put("isUseSMS", com.redmoon.oa.sms.SMSFactory.isUseSMS());
        json.put("linkProps", wpd.getLinkProp());
        json.put("startMode", wpd.getStartMode());
        String strRules = wpd.getRules();
        if (strRules.startsWith("[")) {
            JSONArray rules = JSONArray.parseArray(strRules);
            json.put("rules", rules);
        }
        return new Result<>(json);
    }

    @ApiOperation(value = "保存流程属性", notes = "保存流程属性", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/updateWorkflowProps", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Result<Object> updateWorkflowProps() throws ErrMsgException {
        boolean re;
        WorkflowPredefineMgr wpm = new WorkflowPredefineMgr();
        try {
            re = wpm.modify(request);
        } catch (Exception e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "保存回写", notes = "保存回写", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "writeProp", value = "回写属性", required = false, dataType = "String")
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateWriteBack", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateWriteBack(@RequestParam String typeCode, String writeProp) {
        boolean re;
        try {
            if (writeProp != null && !"".equals(writeProp)) {
                try {
                    SAXBuilder parser = new SAXBuilder();
                    org.jdom.Document docu = parser.build(new InputSource(new StringReader(writeProp)));
                    Element root = docu.getRootElement();
                    // 删除重复的结束事件
                    List flowFinish = root.getChildren("flowFinish");
                    int size = flowFinish.size();
                    if (size > 1) {
                        int i = 0;
                        while (i < size - 1) {
                            Element e = (Element)flowFinish.get(i);
                            root.removeContent(e);
                            i++;
                        }
                    }

                    Format format = Format.getPrettyFormat();
                    ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
                    XMLOutputter xmlOut = new XMLOutputter(format);
                    xmlOut.output(docu, byteRsp);
                    writeProp = byteRsp.toString("utf-8");
                    byteRsp.close();
                } catch (Exception e) {
                    LogUtil.getLog(getClass()).error(e);
                }
            }

            WorkflowPredefineDb wpd = new WorkflowPredefineDb();
            wpd = wpd.getDefaultPredefineFlow(typeCode);
            wpd.setWriteProp(writeProp);
            re = wpd.save();
        } catch (ErrMsgException e) {
            LogUtil.getLog(getClass()).error(e);
            return new Result<>(false);
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "保存外部数据源回写", notes = "保存外部数据源回写", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "writeProp", value = "回写属性", required = true, dataType = "String")
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateWriteBackByDb", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateWriteBackByDb(@RequestParam(value = "typeCode") String typeCode, @RequestParam(value = "writeProp") String writeProp) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        wpd.setWriteDbProp(writeProp);
        return new Result<>(wpd.save());
    }

    @ApiOperation(value = "清除回写", notes = "清除回写", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "internalName", value = "节点名称", required = true, dataType = "String"),
            @ApiImplicitParam(name = "opportunity", value = "时机", required = false, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/clearWriteBack", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> clearWriteBack(@RequestParam(value = "typeCode")String typeCode, @RequestParam(value = "internalName", required = false) String internalName, String opportunity) {
        Element del = null;
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        org.jdom.Document doc = null;
        String writeProp = wpd.getWriteProp();
        if (writeProp != null && !"".equals(writeProp)) {
            SAXBuilder parser = new SAXBuilder();
            try {
                doc = parser.build(new InputSource(new StringReader(writeProp)));
                Element root = doc.getRootElement();
                if ("flowFinish".equals(opportunity)) {
                    Element flowFinish = root.getChild("flowFinish");
                    if (flowFinish != null) {
                        root.removeContent(flowFinish);
                    }
                } else {
                    List list = root.getChildren("nodeFinish");
                    if (list != null) {
                        Iterator ir = list.iterator();
                        while (ir.hasNext()) {
                            Element nodeFinish = (Element) ir.next();
                            String internalNodeText = nodeFinish.getChildText("internalName");
                            if (internalName.equals(internalNodeText)) {                             //节点存在先删除
                                del = nodeFinish;
                                break;
                            }
                        }
                    }

                    if (del != null) {
                        root.removeContent(del);
                    }
                }
            } catch (JDOMException | IOException e) {
                LogUtil.getLog(getClass()).error(e);
                return new Result<>(false, e.getMessage());
            }
        }

        boolean re = true;
        if (doc != null) {
            Format format = Format.getPrettyFormat();
            ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
            XMLOutputter xmlOut = new XMLOutputter(format);
            try {
                xmlOut.output(doc, byteRsp);
                writeProp = byteRsp.toString("utf-8");
                byteRsp.close();
                wpd.setWriteProp(writeProp);
                re = wpd.save();
            } catch (IOException e) {
                LogUtil.getLog(getClass()).error(e);
            }
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "清除外部回写", notes = "清除外部回写", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "internalName", value = "节点名称", required = false, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/clearWriteBackByDb", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> clearWriteBackByDb(@RequestParam(value = "typeCode") String typeCode, @RequestParam(value = "internalName", required = false) String internalName) {
        boolean re = false;
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        SAXBuilder parser = new SAXBuilder();
        String writeProp = wpd.getWriteDbProp();
        Element del = null;
        org.jdom.Document doc = null;
        String timestamp = ParamUtil.get(request,"timestamp");
        if (writeProp != null && !"".equals(writeProp)) {
            Iterator ir = null;
            try {
                doc = parser.build(new InputSource(new StringReader(writeProp)));
                Element root = doc.getRootElement();
                if ("flowFinish".equals(timestamp)){
                    Element  flowFinish = root.getChild("flowFinish");
                    if (flowFinish!=null) {
                        root.removeContent(flowFinish);
                    }
                } else {
                    List list = root.getChildren("nodeFinish");
                    if (list!=null) {
                        ir = list.iterator();
                    }
                    while (ir!=null&&ir.hasNext()){
                        Element nodeFinish = (Element)ir.next();
                        String  internalNodeText = nodeFinish.getChildText("internalName");
                        if (internalName.equals(internalNodeText)){                             //节点存在先删除
                            del = nodeFinish;
                        }
                    }
                    if (del!=null) {
                        root.removeContent(del);
                    }
                }

                Format format = Format.getPrettyFormat();
                ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
                XMLOutputter xmlOut = new XMLOutputter(format);
                xmlOut.output(doc, byteRsp);
                writeProp = byteRsp.toString("utf-8");
                byteRsp.close();
                wpd.setWriteDbProp(writeProp);
                re = wpd.save();
            } catch (JDOMException | IOException e) {
                LogUtil.getLog(getClass()).error(e);
            }
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "取事件脚本", notes = "取事件脚本", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "internalName", value = "节点名称", required = false, dataType = "String"),
            @ApiImplicitParam(name = "eventType", value = "事件类型", required = false, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getEventScript", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getEventScript(@RequestParam(value = "typeCode") String typeCode, @RequestParam(value = "internalName", required = false) String internalName, @RequestParam(value = "eventType", required = false) String eventType) {
        WorkflowPredefineMgr wpfm = new WorkflowPredefineMgr();
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        String scripts = wpd.getScripts();

        Leaf lf = new Leaf();
        lf = lf.getLeaf(typeCode);

        if (StrUtil.isEmpty(eventType)) {
            if (StrUtil.isEmpty(internalName)) {
                eventType = "onFinish";
            } else {
                eventType = "validate";
            }
        }

        String scriptStr = "";
        if (StrUtil.isEmpty(internalName)) {
            // out.print(StrUtil.p_center("请选择节点！"));
            // return;
            if ("onFinish".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getOnFinishScript(scripts));
            }
            else if ("discard".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getDiscardScript(scripts));
            }
            else if ("deleteValidate".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getDeleteValidateScript(scripts));
            }
            else if ("recall".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getRecallScript(scripts));
            }
            else if ("preInit".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getPreInitScript(scripts));
            }
            else {
                // form_js
                scriptStr = FileUtil.ReadFile(Global.getRealPath() + "flow/form_js/form_js_" + lf.getFormCode() + ".jsp", "utf-8");
                scriptStr = StrUtil.HtmlEncode(scriptStr);
            }
        }
        else {
            if ("validate".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getValidateScript(scripts, internalName));
            }
            else if ("actionReturn".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getActionReturnScript(scripts, internalName));
            }
            else if ("actionReturned".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getActionReturnedScript(scripts, internalName));
            }
            else if ("preDispose".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getActionPreDisposeScript(scripts, internalName));
            }
            else if ("actionActive".equals(eventType)) {
                scriptStr = StrUtil.getNullStr(wpfm.getActionActiveScript(scripts, internalName));
            }
            else {
                scriptStr = StrUtil.getNullStr(wpfm.getActionFinishScript(scripts, internalName));
            }
        }

        JSONObject json = new JSONObject();
        json.put("script", scriptStr);
        return new Result<>(json);
    }

    @ApiOperation(value = "保存流程节点上的事件脚本", notes = "保存流程节点上的事件脚本", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "internalName", value = "节点名称", required = true, dataType = "String"),
            @ApiImplicitParam(name = "eventType", value = "事件类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "script", value = "脚本", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateEventScriptByNode", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateEventScriptByNode(@RequestParam(value = "typeCode") String typeCode, @RequestParam(value = "internalName") String internalName, @RequestParam(value = "eventType") String eventType, @RequestParam(value = "script") String script) {
        WorkflowPredefineMgr wpfm = new WorkflowPredefineMgr();
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);

        boolean re;
        if ("validate".equals(eventType)) {
            re = wpfm.saveValidateScript(wpd, internalName, script);
        } else if ("actionReturn".equals(eventType)) {
            re = wpfm.saveActionReturnScript(wpd, internalName, script);
        } else if ("actionReturned".equals(eventType)) {
            re = wpfm.saveActionReturnedScript(wpd, internalName, script);
        } else if ("preDispose".equals(eventType)) {
            re = wpfm.saveActionPreDisposeScript(wpd, internalName, script);
        } else if ("actionActive".equals(eventType)) {
            re = wpfm.saveActionActiveScript(wpd, internalName, script);
        } else if ("preInit".equals(eventType)) {
            re = wpfm.savePreInitScript(wpd, script);
        } else {
            re = wpfm.saveActionFinishScript(wpd, internalName, script);
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "保存流程的事件脚本", notes = "保存流程的事件脚本", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "eventType", value = "事件类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "script", value = "脚本", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateEventScriptByFlow", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateEventScriptByFlow(@RequestParam(value = "typeCode") String typeCode, @RequestParam(value = "eventType") String eventType, @RequestParam(value = "script") String script) {
        WorkflowPredefineMgr wpfm = new WorkflowPredefineMgr();
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);

        boolean re = false;
        if ("onFinish".equals(eventType)) {
            re = wpfm.saveOnFinishScript(wpd, script);
        }
        else if ("discard".equals(eventType)) {
            re = wpfm.saveDiscardScript(wpd, script);
        }
        else if ("recall".equals(eventType)) {
            re = wpfm.saveRecallScript(wpd, script);
        }
        else if ("deleteValidate".equals(eventType)) {
            re = wpfm.saveDeleteValidateScript(wpd, script);
        }
        /*else if ("form_js".equals(eventType)) {
            Leaf lf = new Leaf();
            lf = lf.getLeaf(typeCode);

            FileUtil.WriteFile(Global.getRealPath() + "/flow/form_js/form_js_" + lf.getFormCode() + ".jsp", script, "utf-8");
            re = true;
        }*/
        else if ("preInit".equals(eventType)) {
            re = wpfm.savePreInitScript(wpd, script);
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "进入回写页面", notes = "进入回写页面", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getWriteBackPage", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getWriteBackPage(String typeCode) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        String writeProp = wpd.getWriteProp(); //从数据库获取回写信息

        JSONObject json = new JSONObject();
        json.put("writeProp", writeProp);
        return new Result<>(json);
    }

    @ApiOperation(value = "进入回写外部数据页面", notes = "进入回写外部数据页面", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getWriteBackPageByDb", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getWriteBackPageByDb(String typeCode) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        String writeProp = wpd.getWriteDbProp();

        JSONObject json = new JSONObject();
        json.put("writeProp", writeProp);
        return new Result<>(json);
    }

    @ApiOperation(value = "取得回写外部数据时表中的字段", notes = "取得回写外部数据时表中的字段", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "tableName", value = "表名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "dbSource", value = "数据源名称", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getTableColumns", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getTableColumns(@RequestParam(value = "tableName") String tableName,  @RequestParam(value = "dbSource") String dbSource) {
        JSONArray ary = new JSONArray();
        String sql = "select * from " + tableName;
        com.cloudwebsoft.framework.db.Connection conn = new com.cloudwebsoft.framework.db.Connection(dbSource);
        try {
            conn.setMaxRows(1); //尽量减少内存的使用
            ResultSet rs = conn.executeQuery(sql);
            ResultSetMetaData rm = rs.getMetaData();
            int colCount = rm.getColumnCount();
            for (int i = 1; i <= colCount; i++) {
                int colType = rm.getColumnType(i);
                int fieldType = QueryScriptUtil.getFieldTypeOfDBType(colType);
                JSONObject json = new JSONObject();
                json.put("name", rm.getColumnName(i));
                if (fieldType == FormField.FIELD_TYPE_DOUBLE || fieldType == FormField.FIELD_TYPE_FLOAT || fieldType == FormField.FIELD_TYPE_INT || fieldType == FormField.FIELD_TYPE_LONG || fieldType == FormField.FIELD_TYPE_PRICE) {
                    json.put("type", "number");
                } else {
                    json.put("type", "string");
                }
                ary.add(json);
            }
        } catch (SQLException e) {
            LogUtil.getLog(getClass()).error(e);
        } finally {
            conn.close();
        }

        return new Result<>(ary);
    }

    @ApiOperation(value = "取得流程中的显示规则", notes = "取得流程中的显示规则", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/getViewRule", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> getViewRule(String typeCode) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        String views = wpd.getViews();

        JSONObject json = new JSONObject();
        json.put("views", views);
        // 是否使用表单中的显示规则
        json.put("isUseFormViewRule", wpd.isUseFormViewRule());
        return new Result<>(json);
    }

    @ApiOperation(value = "从表单中复制显示规则", notes = "从表单中复制显示规则", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/copyViewRule", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> copyViewRule(String typeCode) {
        Leaf lf = new Leaf();
        lf = lf.getLeaf(typeCode);
        if (lf == null) {
            return new Result<>(false, "流程类型不存在");
        }
        String formCode = lf.getFormCode();
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);

        String xml = fd.getViewSetup();
        int p = xml.indexOf("<views>");
        int q = xml.indexOf("</views>");
        if (p == -1 || q == -1) {
            return new Result<>(false, "表单中的显示规则不存在或格式错误");
        }
        xml = xml.substring(p + 7, q);
        xml = "<actions><action internalName=\"defaultNode\">" + xml + "</action></actions>";

        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getPredefineFlowOfFree(typeCode);
        wpd.setViews(xml);
        return new Result<>(wpd.save());
    }

    @ApiOperation(value = "将显示规则同步至表单", notes = "将显示规则同步至表单", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/syncViewRule", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> syncViewRule(@RequestParam String typeCode) {
        Leaf lf = new Leaf();
        lf = lf.getLeaf(typeCode);
        if (lf == null) {
            return new Result<>(false, "流程类型不存在");
        }

        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);

        String formCode = lf.getFormCode();
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);

        String xml = wpd.getViews();
        String token = "<action internalName=\"defaultNode\">";
        int p = xml.indexOf(token);
        int q = xml.indexOf("</action>");
        if (p == -1 || q == -1) {
            return new Result<>(false, "流程中的显示规则不存在或格式错误");
        }
        xml = xml.substring(p + token.length(), q);
        xml = "<config><views>" + xml + "</views></config>";
        fd.setViewSetup(xml);
        return new Result<>(fd.saveContent());
    }

    @ApiOperation(value = "保存流程中的显示规则", notes = "保存流程中的显示规则", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "viewRule", value = "流程类型", required = false, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/flow/updateViewRule", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateViewRule(@RequestParam String typeCode, String viewRule) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        wpd.setViews(viewRule);
        return new Result<>(wpd.save());
    }

    @ApiOperation(value = "置是否使用表单中的规则", notes = "置是否使用表单中的规则", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
            @ApiImplicitParam(name = "isUseFormViewRule", value = "是否使用表单显示规则", required = false, dataType = "Boolean"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/flow/setViewRule", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> setViewRule(@RequestParam String typeCode, Boolean isUseFormViewRule) {
        WorkflowPredefineDb wpd = new WorkflowPredefineDb();
        wpd = wpd.getDefaultPredefineFlow(typeCode);
        wpd.setUseFormViewRule(isUseFormViewRule);
        return new Result<>(wpd.save());
    }

    @ApiOperation(value = "编辑自由流程页面", notes = "编辑自由流程页面", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeCode", value = "流程类型", required = true, dataType = "String"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/flow/editFreeFlowPage", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> editFreeFlowPage(String typeCode) {
        WorkflowPredefineDb wfp = new WorkflowPredefineDb();
        wfp = wfp.getPredefineFlowOfFree(typeCode);
        String[][] rolePrivs = wfp.getRolePrivsOfFree();
        int privLen = rolePrivs.length;

        com.redmoon.oa.flow.Leaf flf = new com.redmoon.oa.flow.Leaf();
        flf = flf.getLeaf(wfp.getTypeCode());
        FormDb fd = new FormDb();
        fd = fd.getFormDb(flf.getFormCode());
        if (!fd.isLoaded()) {
            return new Result<>(false, "表单: " + flf.getFormCode() + " 不存在");
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("isRecall", wfp.isRecall());
        jsonObject.put("isReactive", wfp.isReactive());
        jsonObject.put("isReply", wfp.isReply());

        JSONArray ary = new JSONArray();
        String code;
        String desc;
        MacroCtlMgr mm = new MacroCtlMgr();
        RoleDb roleDb = new RoleDb();
        Vector<RoleDb> result = roleDb.list();
        for (RoleDb rd : result) {
            code = rd.getCode();
            desc = rd.getDesc();
            String chk0 = "", chk1 = "", chk2 = "", chk3 = "", chk4 = "", chk5 = "", chk6 = "", chk7 = "";
            String fields = "", fieldNames = "";
            for (String[] rolePriv : rolePrivs) {
                if (code.equals(rolePriv[0])) {
                    chk0 = "checked";
                    chk1 = "1".equals(StrUtil.getNullStr(rolePriv[1])) ? "checked" : "";
                    chk2 = "1".equals(StrUtil.getNullStr(rolePriv[2])) ? "checked" : "";
                    chk3 = "1".equals(StrUtil.getNullStr(rolePriv[3])) ? "checked" : "";
                    chk4 = "1".equals(StrUtil.getNullStr(rolePriv[4])) ? "checked" : "";
                    chk5 = "1".equals(StrUtil.getNullStr(rolePriv[5])) ? "checked" : "";
                    chk6 = "1".equals(StrUtil.getNullStr(rolePriv[6])) ? "checked" : "";
                    fields = StrUtil.getNullStr(rolePriv[7]).replaceAll("\\|", ",");

                    if (rolePriv.length >= 9) {
                        chk7 = "1".equals(StrUtil.getNullStr(rolePriv[8])) ? "checked" : "";
                    }

                    String[] fieldAry = fields.split(",");
                    // 找出嵌套表
                    FormDb nestfd = new FormDb();
                    Vector<FormDb> vfd = new Vector<>();
                    Vector<FormField> v = fd.getFields();
                    for (FormField ff : v) {
                        if (ff.getType().equals(FormField.TYPE_MACRO)) {
                            MacroCtlUnit mu = mm.getMacroCtlUnit(ff.getMacroType());
                            if (mu != null && mu.getNestType() != MacroCtlUnit.NEST_TYPE_NONE) {
                                String nestFormCode = ff.getDefaultValue();
                                String defaultVal;
                                if (mu.getNestType() == MacroCtlUnit.NEST_DETAIL_LIST) {
                                    defaultVal = StrUtil.decodeJSON(ff.getDescription());
                                } else {
                                    defaultVal = StrUtil.decodeJSON(ff.getDefaultValueRaw()); // ff.getDefaultValueRaw()
                                }
                                JSONObject json = JSONObject.parseObject(defaultVal);
                                if (json == null) {
                                    LogUtil.getLog(getClass()).error(ff.getTitle() + " 嵌套表的配置错误");
                                } else {
                                    nestFormCode = json.getString("destForm");

                                    FormDb nestFormDb = nestfd.getFormDb(nestFormCode);
                                    vfd.addElement(nestFormDb);
                                }
                            }
                        }
                    }

                    int len = fieldAry.length;
                    for (String s : fieldAry) {
                        if (StrUtil.isEmpty(fieldNames)) {
                            if (s.startsWith("nest.")) {
                                for (FormDb formDb : vfd) {
                                    nestfd = formDb;
                                    String nestFieldName = nestfd.getFieldTitle(s.substring("nest.".length()));
                                    if (!"".equals(nestFieldName)) {
                                        fieldNames = nestFieldName + "(嵌套表)";
                                        break;
                                    }
                                }
                            } else {
                                fieldNames = fd.getFieldTitle(s);
                            }
                        } else {
                            if (s.startsWith("nest.")) {
                                for (FormDb formDb : vfd) {
                                    nestfd = formDb;
                                    String nestFieldName = nestfd.getFieldTitle(s.substring("nest.".length()));
                                    if (!"".equals(nestFieldName)) {
                                        fieldNames += "," + nestFieldName + "(嵌套表)";
                                        break;
                                    }
                                }
                            } else {
                                fieldNames += "," + fd.getFieldTitle(s);
                            }
                        }
                    }
                    break;
                }
            }
            JSONObject json = new JSONObject();
            json.put("roleCode", rd.getCode());
            json.put("roleDesc", rd.getDesc());
            json.put("isRoleSelected", "checked".equals(chk0));
            json.put("canSee", "checked".equals(chk1));
            json.put("canStop", "checked".equals(chk2));
            json.put("canDiscard", "checked".equals(chk4));
            json.put("canDel", "checked".equals(chk5));
            json.put("canDelAttach", "checked".equals(chk6));
            json.put("fieldNames", fieldNames);
            json.put("fields", fields);
            ary.add(json);
        }
        jsonObject.put("list", ary);
        return new Result<>(jsonObject);
    }

    @ApiOperation(value = "保存自由流程", notes = "保存自由流程", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jsonObject", value = "参数", required = true, dataType = "JSONObject"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @PreAuthorize("hasAnyAuthority('admin', 'admin.flow')")
    @ResponseBody
    @RequestMapping(value = "/flow/updateFreeFlow", method = RequestMethod.POST, produces = {"text/html;", "application/json;charset=UTF-8;"})
    public Result<Object> updateFreeFlow(@RequestBody com.alibaba.fastjson.JSONObject jsonObject) {
        WorkflowPredefineMgr wpm = new WorkflowPredefineMgr();
        return new Result<>(wpm.modifyFree(jsonObject));
    }
}
